package com.xuecheng.order.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.service.WxPayService;

import com.xuecheng.api.agent.CoursePubIndexApiAgent;
import com.xuecheng.api.learning.model.dto.OrdersDTO;

import com.xuecheng.api.order.model.pay.PayCodeUrlResult;
import com.xuecheng.api.search.model.CoursePubIndexDTO;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.enums.order.OrderDealStatusEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.PaymentUtil;
import com.xuecheng.common.util.StringUtil;

import com.xuecheng.order.common.constant.OrderErrorCode;
import com.xuecheng.order.convert.OrderConvert;
import com.xuecheng.order.entity.Orders;

import com.xuecheng.order.entity.Pay;
import com.xuecheng.order.mapper.OrdersMapper;
import com.xuecheng.order.service.OrdersService;

import com.xuecheng.order.service.PayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.net.InetAddress;
import java.time.LocalDateTime;

/**
 * <p>
 * 订单 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements OrdersService {
    @Autowired
    private CoursePubIndexApiAgent searchIndexApiAgent;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private PayService payService;
    /*
    * 业务分析：
    *   1.判断关键数据
    *       coursePubId   username
    *   2.判断业务数据
    *       课程发布数据
    *   3.保存订单数据
    *       判断订单数据是否存在：coursePubId username（一个人对于一门课只有一个订单）
    *         根据订单支付状态来判断：初始化态
    *           如果没有
    *               创建订单:新建的订单状态为--初始态
    *           如果有
    *              如果订单数据存在，需要获得最新的课程价格并修改订单的价格数据--活动
    *
    *   4.将结果数据转为DTO并返回
    * */
    @Transactional
    public OrdersDTO createOrder(String username,Long coursePubId) {
        // 1.判断关键数据
        //      coursePubId   username
        if (ObjectUtils.isEmpty(coursePubId)||
                StringUtil.isBlank(username)
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        //  2.判断业务数据
        //      课程发布数据
        RestResponse<CoursePubIndexDTO> restResponse = searchIndexApiAgent.getCoursePubIndexById4s(coursePubId);
        if (!(restResponse.isSuccessful())) {
            ExceptionCast.castWithCodeAndDesc(restResponse.getCode(),restResponse.getMsg());
        }
        CoursePubIndexDTO coursePub = restResponse.getResult();
        //  3.保存订单数据
        //      判断订单数据是否存在：coursePubId username（一个人对于一门课只有一个订单）
        //      根据订单支付状态来判断：初始化态
        LambdaQueryWrapper<Orders> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Orders::getUserName, username);
        queryWrapper.eq(Orders::getCoursePubId, coursePubId);
        queryWrapper.eq(Orders::getStatus,new Integer(OrderDealStatusEnum.ORDER_DEAL_INIT_STATUS.getCode()) );
        Orders orders = this.getOne(queryWrapper);
        boolean result = false;
        if (ObjectUtils.isEmpty(orders)) {
        //          如果没有
        //              创建订单
            orders = new Orders();
            // 订单编号：有学成的标识+时间+唯一标识
            orders.setOrderNo(PaymentUtil.genUniquePayOrderNo());
            orders.setCoursePubId(coursePub.getIndexId());
            orders.setCoursePubName(coursePub.getName());
            orders.setCompanyId(coursePub.getCompanyId());
            orders.setUserName(username);
            orders.setInitialPrice(coursePub.getPrice());
            orders.setPrice(coursePub.getPrice());
            orders.setStatus(new Integer(OrderDealStatusEnum.ORDER_DEAL_INIT_STATUS.getCode()));
            result = this.save(orders);
        } else {
            // 修改订单的价格
            // 如果订单数据存在，需要获得最新的课程价格并修改订单的价格数据--活动
            LambdaUpdateWrapper<Orders> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(Orders::getPrice, coursePub.getPrice());
            updateWrapper.set(Orders::getChangeDate, LocalDateTime.now());
            updateWrapper.eq(Orders::getId, orders.getId());
            result = this.update(updateWrapper);
        }
        if (!result) {
            ExceptionCast.cast(OrderErrorCode.E_160015);
        }
        //  4.将结果数据转为DTO并返回
        Orders po = this.getById(orders.getId());
        OrdersDTO resultDTO = OrderConvert.INSTANCE.entity2dto(po);
        return resultDTO;
    }
    /*
          PS:该方法不管也什么异常，都需要使用PayCodeUrlResult数据进行封装
      * 业务分析：
      *   1.判断关键数据
      *       orderNo username
      *   2.判断业务数据
      *       订单数据
      *           判断是否存在：orderNo username status：初始态
          特别说明：本次的操作由于无法向外抛出异常，是的事务无法回顾：
              1.先操作第三方支付系统
              2.操作本地数据
          3.和wx平台进行交互获得支付链接地址
          4.保存订单支付数据
      *
      *
      * */
    @Override
    @Transactional
    public PayCodeUrlResult createPayCodeResult(String orderNo, String username) {
        // 1.判断关键数据
        //      orderNo username
        if (StringUtil.isBlank(orderNo)||
                StringUtil.isBlank(username)
        ) {
            return PayCodeUrlResult.failed(CommonErrorCode.E_100101.getDesc());
        }
        //  2.判断业务数据
        //      订单数据
        //          判断是否存在：orderNo username status：初始态
        LambdaQueryWrapper<Orders> ordersQueryWrapper = new LambdaQueryWrapper<>();
        ordersQueryWrapper.eq(Orders::getUserName, username);
        ordersQueryWrapper.eq(Orders::getOrderNo, orderNo);
        String statusCodeInt = OrderDealStatusEnum.ORDER_DEAL_INIT_STATUS.getCode();
        ordersQueryWrapper.eq(Orders::getStatus, statusCodeInt);
        int count = this.count(ordersQueryWrapper);
        if (count < 1) {
            return PayCodeUrlResult.failed(OrderErrorCode.E_160008.getDesc());
        }
        //  3.和wx平台进行交互获得支付链接地址
        // 3.1 创建wx统一下单请求对象
        // 根据orders数据进行统一下单
        ordersQueryWrapper = new LambdaQueryWrapper<>();
        ordersQueryWrapper.eq(Orders::getOrderNo, orderNo);
        Orders orders = this.getOne(ordersQueryWrapper);
        PayCodeUrlResult urlResult = null;
        try {
            WxPayUnifiedOrderRequest unifiedOrderRequest = new WxPayUnifiedOrderRequest();
            unifiedOrderRequest.setBody("课程名称："+orders.getCoursePubName());
            unifiedOrderRequest.setOutTradeNo(orders.getOrderNo());
            Integer yuan = WxPayUnifiedOrderRequest.yuanToFen(orders.getPrice().toString());
            unifiedOrderRequest.setTotalFee(yuan);
            // 获得程序服务所在服务的ip地址
            unifiedOrderRequest.setSpbillCreateIp(InetAddress.getLocalHost().getHostAddress());
            unifiedOrderRequest.setProductId("课程id："+orders.getCoursePubId());
            // 3.2 获得响应数据
            WxPayUnifiedOrderResult unifiedOrderResult = wxPayService.unifiedOrder(unifiedOrderRequest);
            // 3.3 解析响应数据--支付二维码的url
            urlResult = null;
            String returnCode = unifiedOrderResult.getReturnCode();
            String resultCode = unifiedOrderResult.getResultCode();
            if (PayCodeUrlResult.WX_PAY_SUCCESS_FLAG.equalsIgnoreCase(returnCode) &&
                    PayCodeUrlResult.WX_PAY_SUCCESS_FLAG.equalsIgnoreCase(resultCode)
            ) {
                // 获得支付二维码的url成功
                urlResult = PayCodeUrlResult.success(unifiedOrderResult.getCodeURL());
            } else {
                // 获得支付二维码的url失败
                log.error(OrderErrorCode.E_160016.getDesc()+" errCode : {} , errMsg : {}",
                        unifiedOrderResult.getErrCode(),unifiedOrderResult.getErrCodeDes());
                return PayCodeUrlResult.failed(OrderErrorCode.E_160016.getDesc());
            }
        } catch (Exception e) {
            log.error(OrderErrorCode.E_160016.getDesc()+" errMsg : {}",e.getMessage());
            return PayCodeUrlResult.failed(OrderErrorCode.E_160016.getDesc());
        }
        //  4.保存订单支付数据
        // 判断订单支付数据是否存在
        //     orderid  username  companyid  status
        LambdaQueryWrapper<Pay> payQueryWrapper = new LambdaQueryWrapper<>();
        payQueryWrapper.eq(Pay::getOrderId, orders.getId());
        payQueryWrapper.eq(Pay::getUserName, username);
        payQueryWrapper.eq(Pay::getCompanyId, orders.getCompanyId());
        payQueryWrapper.eq(Pay::getStatus, PayCodeUrlResult.NOT_PAY);
        // 如果不存在
        //     给订单创建出一个支付数据
        // 如果存在
        //     不作操作
        int payCount = payService.count(payQueryWrapper);
        if (payCount < 1) {
            Pay pay = new Pay();
            pay.setUserName(username);
            pay.setCompanyId(orders.getCompanyId());
            pay.setOrderId(orders.getId());
            pay.setStatus(PayCodeUrlResult.NOT_PAY);
            pay.setPayMethod(PayCodeUrlResult.WX_PAY_FLAG);
            // 实收金额和付款金额在支付后的通知中再去赋值，本次秩序赋值订单金额即可
            pay.setTotalAmount(new BigDecimal(orders.getPrice().toString()));
            boolean payResult = payService.save(pay);
            if (!payResult) {
                return PayCodeUrlResult.failed(OrderErrorCode.E_160017.getDesc());
            }
        }
        return urlResult;
    }


}
